
a = 2;
var a; // 变量提升， 其实在最前面就执行了

console.log(a) // 2  结果和var句声明没有什么关系


console.log(b)
/* 在编译阶段， 在块级作用域中，如果有b，继续下面， 如果没有b， 就开辟空间声明一个b*/
var b = 1; // undefined   var 在编译阶段被执行了，不会报错的。


/**
 * 其实编译一个var a = 2; 编译器是分为两个过程的， 第一 编译器先执行 var a；第二 运行阶段执行 a = 2 操作
 */

// 函数声明会提升到当前块作用域的最上面
foo() // 这里是不会报错的， 因为直接声明的foo函数， 提升了， 没事儿
function foo() {
    console.log(a) // 这里不会报错， 但是调用的是 undefined， 使用let 或者const 就直接报错了都。
    var a = 10;
}

foo()
function foo1() {
    var a ;
    console.log(a) // undefined
    a  = 10;
}

ck() // TypeError， 函数表达式格式， 这里的ck会是没有定义的。
var ck = function kb (){
    console.log('kb')
}

// 这段代码被编译成
var ck;
ck() // TypeError 这个ck提升后， 其实是变量，而不是函数。 所以报类型错误
ck = function (){
    // 所以这里的kb其实会报ReferenceError
    var kb = this;
}

/**
 * 注意的是： 变量和函数都会被提升， 但是， 函数优先！！！！！！！！！！
 * 看下面代码：
 */
foo3(); // 1
var foo3; // 其实这里的foo3被忽略了， 其实还是函数优先， 但是， 函数声明后， 变量声明就被忽略了
function foo3() { console.log( 1 ); // 函数会被提升到最前面， 比如这里的foo3其实调用的就是这里
}
foo3 = function() { console.log( 2 );
};
// 如果加了这一行， 那么， 会输出的就是3了，因为函数声明会覆盖掉上一个函数声明
function foo3() {
    console.log(3)
}


// 上面代码会被编译成
function foo4() {
    console.log(1)
}
foo4()
foo4 = function (){
    console.log(2)
}









